#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/stat.h>
#include <sys/wait.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <fcntl.h>
#include <microhttpd.h>

#include "res.h"

#define PORT 8080
#define MIMETYPE "image/png"

int check_file(char *file, struct MHD_Response **response, struct MHD_Connection *connection, unsigned char **buffer, int *ret,  struct stat *sbuf, int *fd){

	if((-1 == (*fd = open(file, O_RDONLY))) || (0 != fstat(*fd, &(*sbuf)))){
		
		if(*fd != -1) close(*fd);
		const char *errorstr = "<html><body>An internal server error has occurred!</body></html>";
		*response = MHD_create_response_from_buffer(strlen(errorstr), (void*) errorstr, MHD_RESPMEM_PERSISTENT);
		if(*response){
			*ret = MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, *response);
			MHD_destroy_response(*response);
			return MHD_YES;
		}else
			return MHD_NO;
		if(!*ret){
			//if(buffer) free(buffer);

			*response = MHD_create_response_from_buffer(strlen(errorstr), (void*) errorstr, MHD_RESPMEM_PERSISTENT);
			if(*response){
				*ret = MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, *response);
				MHD_destroy_response(*response);					
				return MHD_YES;
			}else
				return MHD_NO;
		}
	}	
}


int answer_to_connection (void *cls, struct MHD_Connection *connection, 
		const char *url, const char *method, const char *version,
		const char *upload_data, size_t *upload_data_size, void **con_cls){

	if(0 != strcmp(method, "GET")) 
		return MHD_NO;
	else{
		unsigned char *buffer = NULL;
		struct MHD_Response *response;
		int ret, fd;
		struct stat sbuf;
		
		if(0 == strncmp(url, "/images", 7) || 0 == strcmp(url, "/favicon.ico")){
			check_file("picture.png", &response, connection, &buffer, &ret, &sbuf, &fd);
			//perror("Error: ");	
			response = MHD_create_response_from_fd_at_offset64(sbuf.st_size, fd, 0);
			MHD_add_response_header(response, "Content-Type", MIMETYPE);

		}else if(0 == strcmp(url, "/watch")){ 
			const char *vid_arg = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "v");
			char *vid_file = calloc(20, 1);
			char *page = malloc(500);

			if(strlen(vid_arg) != 11){
				strcpy(page, "--- Invalid YouTube ID ---");
			}else{
				strcpy(page, "<html><style type=text/css>body{background-color:grey; text-align:center},pre{color:white},video{width:480}</style>\
					<body><form method=get action=/query>New search: <input type=text name=key><input value='->' type=submit></form><video src=\"/video/");
				strcat(page, vid_arg);
				strcat(page, ".webm\" controls autoplay>video tag</video></body></html>");
			}
		
			strcpy(vid_file, vid_arg);
			strcat(vid_file, ".webm");
		
			printf("--> %s\n", vid_file);
			struct stat *buf = malloc(sizeof(struct stat));
			int status;	
			
			if(stat(vid_file, buf) != 0){
				pid_t pid_dl = fork();
				if(!pid_dl){
					char *args[] = {"youtube-dl", "-f", "(webm)[height<=240p]+bestaudio[ext=webm]", vid_arg, "-o", "%(id)s", NULL};
					execv("/usr/bin/youtube-dl", args);
				};
				wait(&status);
			}

			free(vid_file);		
			response = MHD_create_response_from_buffer(strlen (page), (void*) page, MHD_RESPMEM_PERSISTENT);
		}else if(0 == strncmp(url, "/video", 6)){
			
			char *vid_file = calloc(20, 1);
			strncpy(vid_file, &url[7], 16);
			
			//printf("\n\nVIDEO FILE:%s\n", vid_file);
			
			check_file(vid_file, &response, connection, &buffer, &ret, &sbuf, &fd);
			free(vid_file);
			response = MHD_create_response_from_fd_at_offset64(sbuf.st_size, fd, 0);
			MHD_add_response_header(response, "Content-Type", "video/webm");	
		
		}else if(0 == strcmp(url, "/")){	
			const char *page = "<html><body>"
				"<style type=text/css>body{background-color:grey; text-align:center},pre{color:white}</style>"
				"<pre>"	
				"		   _				<br>" 
				"  __ _ _   _ _   _| |_ __ ___   __ _  ___ 	<br>" 
				" / _` | | | | | | | | '_ ` _ \\ / _` |/ _ \\	<br>" 
				"| (_| | |_| | |_| | | | | | | | (_| | (_) |	<br>"
				" \\__,_|\\__, |\\__, |_|_| |_| |_|\\__,_|\\___/	<br>" 
				"       |___/ |___/				<br>" 
				"</pre>"
				"<form method=get action=/query>Search:<input type=text name=key><input value='->' type=submit></form>"
				"<img src='images/picture.png'/></body></html>";
				
			response = MHD_create_response_from_buffer(strlen (page), (void*) page, MHD_RESPMEM_PERSISTENT);
		
		
		}else if(0 == strcmp(url, "/query")){
			char *key = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "key");
			char c = 0;
							
			while(*(key+c) != '\0'){
				if(*(key+c) == 32)
					*(key+c) = '+';
				c++;				
			}
			
			char *page = malloc(10000);
			get_results(key, page);
			response = MHD_create_response_from_buffer(strlen (page), (void*) page, MHD_RESPMEM_PERSISTENT);

		}else{
			const char *page = "You're in the wrong place.";
			response = MHD_create_response_from_buffer(strlen (page), (void*) page, MHD_RESPMEM_PERSISTENT);
		}
		printf("\tURL: %s", url);
		struct sockaddr_in *addr = (struct sockaddr_in *) MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr;
		char *ip = inet_ntoa(addr->sin_addr);
		printf("\tIP: %s\n", ip);
		
		ret = MHD_queue_response(connection, MHD_HTTP_OK, response); 
		MHD_destroy_response(response);
		
		//printf("Version: %s URL: %s Method: %s\n", version, url, method);
		return ret;	
	}
}

int main(){
	struct MHD_Daemon *daemon;
	//daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
	//	&answer_to_connection, NULL, MHD_OPTION_END);
	daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, PORT, NULL, NULL,
		&answer_to_connection, NULL, MHD_OPTION_END);
	

	if(NULL == daemon) return 1;
	perror("Error:");
	getchar();
	MHD_stop_daemon(daemon);
	return 0;
}

